/*
 * Created on 30 avr. 2005
 */
package communication.thirdLayer;

import java.util.*;
import communication.pack.*;
import kernel.*;
import communication.*;
import objects.*;

/**
 * @author gerard 
 */
public class AODVProtocol extends ThirdLayerProtocol {

    /**
     * If an object of the type RouterAODV manages all the functioning of a node
     * in the network, an object of the type AODVProtocol manages the
     * functioning of all the nodes in the network.
     */
    public final static int DataPackageMaxsize = 1000;

    /**
     * Time to say Hello to all the neighbors.
     */
    public final static int helloTime = 10000;// temps attente avant envoi

    // Hello

    /**
     * Time to delete a destination since it hasn't been used
     */
    public final static int nonUsedPurgeTime = 15000;

	
    /**
     * Constructor of an object AODVProtocol from an object Simulator
     * @param sim
     */
    public AODVProtocol(Simulator sim) {
	super(sim);
    }

    /**
     * @return the name of this protocol in a string
     */
    public String getProtocolName(){
	return "AODV";
    }
	
    /**
     * time to delete a neighbor since he hasn't said hello
     * @return the period of time (in milisecond) in which 
     * if the station doesn't hear hello from its neighbors, 
     * it will delete all the routingTableEntry which lead to the
     * missing neighbors or use these neighbors
     */
    public double getHelloPurgeTime() {
	return 2 * helloTime;
    }

    /**
     * @return the period of time (in milisecond) in which the station must say hello 
     * once to all of its neighbors
     */
    public double getHelloTime() {
	return helloTime;
    }
		
    /**
     * 
     * @return the period of time (in milisecond) in which if a routingTableEntry hasn't been 
     * used, it will be deleted
     */
    public double getNonUsedPurgeTime() {
	return nonUsedPurgeTime;
    }

    /**
     * Treatment of all the packages that arrive to each station in the network 
     */
    public void packagesTreatment() {
	Vector nw = this.getNetwork();
	for (int i = 0; i < nw.size(); i++) {
	    RouterAODV ra = (RouterAODV) nw.elementAt(i);
	    LinkedList ll = (this.getMySim().getCommunicationManager()
			     .getTLManager().getCurrentPackages()).myPackages(ra.getStation());
	    for (int j = 0; j < ll.size(); j++) {
		IdentifiedCurrentPackage cr = (IdentifiedCurrentPackage) ll
		    .removeFirst();
		if (!cr.isReceiver()) {
		    ra.packageTreatment(cr.getCurrentPackage(), cr
					.getCurrentStation());
		}
	    }
	}
    }

    /**
     * Send hello of each station in the network to its neighbors
     */
    public void routesMaintenance() {
	if (this.getNetwork().size() > 0) {

	    for (int i = 0; i < this.getNetwork().size(); i++) {
		RouterAODV ra = (RouterAODV) this.getNetwork().elementAt(i);
		HelloAODV hello = new HelloAODV(ra.getStation(), ra
						.getNoSequence(), 0, ra.getNoRequest(), 1);
		ra.sendToAllNeighbors(hello);
	    }
	}
    }

    /**
     * This function will look at every routing table entry of the routing table
     * of every station in the network, and delete this entry if it hasn't been 
     * used for a long time and is no longer valid
     */
    public void timingPurge() {
	for (int i = 0; i < this.getNetwork().size(); i++) {
	    RouterAODV ra = (RouterAODV) this.getNetwork().elementAt(i);
	    for (int j = 0; j < ra.getRoutingTable().size(); j++) {
		RoutingTableEntry entry = (RoutingTableEntry) ra
		    .getRoutingTable().elementAt(j);
		// Cas d'une destination
		if (entry.getTimer() > this.getNonUsedPurgeTime())
		    ra.removeRoutingTableEntry(entry);
		// Cas d'un voisin
		else if ((entry.getStepCount() == 1)
			 && (entry.getTimer() > this.getHelloPurgeTime())) {
		    ra.removeRoutingTableEntry(entry);
		}
	    }
	}
    }

    /**
     * Treatment of a failed CurrentCommunication
     * 
     * @param we
     */
    public void failedCommunicationTreatment(WishedEmission we) {

	// 1.Remove its package from CurrentPackages.sendingPackages
	SMPackage p = this.getMySim().getCommunicationManager().getTLManager()
	    .getCurrentPackages().failedCommunication(we);
	// 2.Remove the RoutingTableEntry in the routing table of the station
	// Sender
	Station failedDest = ((Station) we.getDestinatory().get(0));
	we.getTransmitter().getRouter().failedDestination(failedDest);
	// 3.Send Rerr if the source of the failed package is not the
	// transmitter
	// the failed communication
	if(we.getTransmitter()!=p.getSenderId()) 
	    ((RouterAODV) we.getTransmitter().getRouter()).sendRerr(p);

    }

	
    /**
     * Give the name of the protocol
     * 
     * @return the name
     * @uml.property name="protocoleName"
     */
    public String getProtocoleName() {
	return "AODV";
    }

}
